using System;
using System.Collections.Generic;
using System.Text;
using Weazel.Math;

namespace Weazel.Gezel.Simulator.Reference.IpBlocks
{
    [IpBlockAttribute("opbmaster")]
    public class OpbMaster : AbstractIpBlock
    {
        private const string masterRequest = "m_request";
        private const string masterSelect = "m_select";
        private const string masterReadNotWrite = "m_rnw";
        private const string masterDataBus = "m_dbus";
        private const string masterAddressBus = "m_abus";

        private int masterRequestIndex = -1;
        private int masterSelectIndex = -1;
        private int masterReadNotWriteIndex = -1;
        private int masterDataBusIndex = -1;
        private int masterAddressBusIndex = -1;

        private const string opbGrant = "opb_grant";
        private const string opbXferAck = "opb_xfer_ack";
        private const string opbDataBus = "opb_dbus";

        private int opbGrantIndex = -1;
        private int opbXferAckIndex = -1;
        private int opbDataBusIndex = -1;

        public bool MasterRequest
        {
            get { return ioValues[masterRequestIndex] == new Integer("1"); }
        }

        public bool MasterSelect
        {
            get { return ioValues[masterSelectIndex] == new Integer("1"); }
        }

        public bool MasterReadNotWrite
        {
            get { return ioValues[masterReadNotWriteIndex] == new Integer("1"); }
        }

        public uint MasterDataBus
        {
            get { return ioValues[masterDataBusIndex].ToUInt(); }
        }

        public uint MasterAddressBus
        {
            get { return ioValues[masterAddressBusIndex].ToUInt(); }
        }

        public bool OpbXferAck
        {
            set { ioValues[opbXferAckIndex].Assign(value ? 1 : 0); }
        }

        public uint OpbDataBus
        {
            set { ioValues[opbDataBusIndex].Assign(value); }
        }

        public delegate bool RequestBusDelegate(bool request);

        public RequestBusDelegate RequestBus;

        public OpbMaster(string name)
            : base(name)
        {
        }

        public override void SetParameter(string name)
        {
            string field = name.Substring(0, name.IndexOf('='));
            string value = name.Substring(name.IndexOf('=') + 1);

            // no parameters ..
        }

        public override bool CheckTerminal(int n, string tname, IoDirection dir)
        {
            if (tname == masterRequest && dir == IoDirection.Input)
                masterRequestIndex = n;
            else if (tname == masterAddressBus && dir == IoDirection.Input)
                masterAddressBusIndex = n;
            else if (tname == masterReadNotWrite && dir == IoDirection.Input)
                masterReadNotWriteIndex = n;
            else if (tname == masterSelect && dir == IoDirection.Input)
                masterSelectIndex = n;
            else if (tname == masterDataBus && dir == IoDirection.Input)
                masterDataBusIndex = n;


            else if (tname == opbGrant && dir == IoDirection.Output)
                opbGrantIndex = n;
            else if (tname == opbDataBus && dir == IoDirection.Output)
                opbDataBusIndex = n;
            else if (tname == opbXferAck && dir == IoDirection.Output)
                opbXferAckIndex = n;
            else
            {
                // ?
            }

            return true;
        }



        public override void Evaluate(long g, bool topLevelCall)
        {
            if (topLevelCall)
            {
                // update all in signals (direction out from IP)
                foreach (InputSignal i in Inputs)
                {
                    ioValues[(int)ioMap[i]] = i.Evaluate(this, g);

                    //Console.WriteLine(ioValues[(int)ioMap[i]].ToHexadecimalString());

                    //if (ioValues[(int)ioMap[i]].ToHexadecimalString() == "0x20000000")
                    //    Console.WriteLine("hej");
                }
            }

            if (generation != g)
            {
                // this is run (at most) once per cycle

                Run();
                generation = g;

                if (RequestBus == null)
                    throw new NullReferenceException("RequestBus() delegate not set");

                if (RequestBus(ioValues[masterRequestIndex] == new Integer("1")))
                {
                    // bus request grated, assert grant                
                    ioValues[opbGrantIndex].Assign(1);
                }
                else
                {
                    // bus request denied
                    ioValues[opbGrantIndex].Assign(0);
                }

                /*
                if (ioValues[masterRequestIndex] == new Integer("1"))
                {
                    if (RequestBus == null)
                        throw new NullReferenceException("RequestBus() delegate not set");

                    if (RequestBus())
                    {
                        // bus request grated, assert grant                
                        ioValues[opbGrantIndex].Assign(1);
                    }
                    else
                    {
                        // bus request denied
                        ioValues[opbGrantIndex].Assign(0);
                    }
                }*/
            }
        }

        public override void Run()
        {

        }
    }
}
